﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DataTypeBase.cs" company="CodePlex">
//   The MIT License
//   Copyright (c) 2013 Julien Blin
//   
//   Permission is hereby granted, free of charge, to any person obtaining a copy
//   of this software and associated documentation files (the "Software"), to deal
//   in the Software without restriction, including without limitation the rights
//   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//   copies of the Software, and to permit persons to whom the Software is
//   furnished to do so, subject to the following conditions:
//   
//   The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//   
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//   THE SOFTWARE.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace UCodeFirst.DataTypes
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using umbraco.cms.businesslogic.datatype;

    using Umbraco.Core;

    /// <summary>
    /// Base type to define data types.
    /// Don't forget to also add a <see cref="DataTypeAttribute"/> to the class,
    /// otherwise it is not considered a valid definition.
    /// The Name is used as the key for modifications.
    /// </summary>
    public abstract class DataTypeBase
    {
        /// <summary>
        /// Called when synchronizing the data types and allows to alter the editor settings.
        /// </summary>
        /// <param name="existingSettings">
        /// The existing settings. Can be null if the data type didn't exists before the synchronization.
        /// </param>
        /// <returns>
        /// The new settings. Return null for no change.
        /// </returns>
        public virtual List<Setting<string, string>> UpdateSettings(List<Setting<string, string>> existingSettings)
        {
            return null;
        }

        /// <summary>
        /// Creates a list of settings with empty keys and values from <see cref="Enum"/> names.
        /// See <see cref="EnumNameAttribute"/>.
        /// </summary>
        /// <param name="existingSettings">
        /// The existing settings.
        /// </param>
        /// <typeparam name="T">
        /// The <see cref="Enum"/> type.
        /// </typeparam>
        /// <param name="deleteAdditionalValues">
        /// True to delete additional values, false to leave them unattended.
        /// </param>
        /// <returns>
        /// The new settings.
        /// </returns>
        protected List<Setting<string, string>> SettingsFromEnumNames<T>(List<Setting<string, string>> existingSettings, bool deleteAdditionalValues = true)
        {
            return this.SettingsFromEnumNames(existingSettings, typeof(T), deleteAdditionalValues);
        }

        /// <summary>
        /// Creates a list of settings with empty keys and values from <see cref="Enum"/> names.
        /// See <see cref="EnumNameAttribute"/>.
        /// </summary>
        /// <param name="existingSettings">
        /// The existing settings.
        /// </param>
        /// <param name="enumType">
        /// The <see cref="Enum"/> type.
        /// </param>
        /// <param name="deleteAdditionalValues">
        /// True to delete additional values, false to leave them unattended.
        /// </param>
        /// <returns>
        /// The new settings.
        /// </returns>
        protected List<Setting<string, string>> SettingsFromEnumNames(List<Setting<string, string>> existingSettings, Type enumType, bool deleteAdditionalValues = true)
        {
            var result = new List<Setting<string, string>>();
            if (existingSettings != null)
            {
                result.AddRange(existingSettings);
            }

            var enumNames = enumType.GetEnumNamesUsingEnumAttribute().ToList();
            var missingNames = enumNames.Where(x => !result.Select(y => y.Value).InvariantContains(x));
            result.AddRange(missingNames.Select(x => new Setting<string, string> { Key = string.Empty, Value = x }));

            if (deleteAdditionalValues)
            {
                var settingsToDelete = result.Where(x => !enumNames.InvariantContains(x.Value));
                result.RemoveAll(settingsToDelete.Contains);
            }

            return result;
        }
    }
}
